/**
 * this file define QMC58835883 register address
 *
 * @file       QMC58835883_defs.h
 * @date       2024-01-19
 * @version    v0.0.1
 *
 */

#ifndef _QMC58835885_DEF_H_
#define _QMC58835885_DEF_H_

/******************************************************************************/
/*! @name       Header includes                           */
/******************************************************************************/
#ifdef __KERNEL__
#include <linux/types.h>
#include <linux/kernel.h>
#else
#include <stdio.h>
#include <stdint.h>
#include <stddef.h>
#endif

/******************************************************************************/
/*! @name       Common macros                         */
/******************************************************************************/
#ifdef __KERNEL__
#if !defined(UINT8_C) && !defined(INT8_C)
#define INT8_C(x) S8_C(x)
#define UINT8_C(x) U8_C(x)
#endif

#if !defined(UINT16_C) && !defined(INT16_C)
#define INT16_C(x) S16_C(x)
#define UINT16_C(x) U16_C(x)
#endif

#if !defined(INT32_C) && !defined(UINT32_C)
#define INT32_C(x) S32_C(x)
#define UINT32_C(x) U32_C(x)
#endif

#if !defined(INT64_C) && !defined(UINT64_C)
#define INT64_C(x) S64_C(x)
#define UINT64_C(x) U64_C(x)
#endif
#endif

/*! @name C standard macros */
#ifndef NULL
#ifdef __cplusplus
#define NULL 0
#else
#define NULL ((void *)0)
#endif
#endif

/******************************************************************************/
/*! @name        General Macro Definitions                */
/******************************************************************************/
/*! @name  Utility macros */

#define QMC5883_SET_BITS(reg_data, bitname, data) \
    ((reg_data & ~(bitname##_MASK)) |             \
     ((data << bitname##_POS) & bitname##_MASK))

#define QMC5883_GET_BITS(reg_data, bitname) \
    ((reg_data & (bitname##_MASK)) >>       \
     (bitname##_POS))

#define QMC5883_SET_BIT_POS0(reg_data, bitname, data) \
    ((reg_data & ~(bitname##_MASK)) |                 \
     (data & bitname##_MASK))

#define QMC5883_GET_BIT_POS0(reg_data, bitname) (reg_data & (bitname##_MASK))
#define QMC5883_SET_BIT_VAL0(reg_data, bitname) (reg_data & ~(bitname##_MASK))

/*! @name For getting LSB and MSB */
#define QMC5883_GET_LSB(var) (uint8_t)(var & QMC5883_SET_LOW_BYTE)
#define QMC5883_GET_MSB(var) (uint8_t)((var & QMC5883_SET_HIGH_BYTE) >> 8)

#ifndef QMC5883_INTF_RETURN_TYPE
#define QMC5883_INTF_RETURN_TYPE int8_t
#endif

/*! @name For defining absolute values */
#define QMC5883_ABS(a) ((a) > 0 ? (a) : -(a))

/*! @name LSB and MSB mask definitions */
#define QMC5883_SET_LOW_BYTE UINT16_C(0x00FF)
#define QMC5883_SET_HIGH_BYTE UINT16_C(0xFF00)
#define QMC5883_SET_LOW_NIBBLE UINT8_C(0x0F)

/*! @name For enable and disable */
#define QMC5883_ENABLE UINT8_C(1)
#define QMC5883_DISABLE UINT8_C(0)

/*! @name To define TRUE or FALSE */
#define QMC5883_TRUE UINT8_C(1)
#define QMC5883_FALSE UINT8_C(0)

/*! @name Macro to define maximum length of read */
#define QMC5883_MAX_LEN UINT8_C(6)

/*! @name To define sensor interface success code */
#define QMC5883_INTF_RET_SUCCESS INT8_C(0)

/*! @name To define success code */
#define QMC5883_OK INT8_C(0)

/*! @name To define error codes */
#define QMC5883_E_NULL_PTR INT8_C(-1)
#define QMC5883_E_COM_FAIL INT8_C(-2)
#define QMC5883_E_DEV_NOT_FOUND INT8_C(-3)
#define QMC5883_E_OUT_OF_RANGE INT8_C(-4)
#define QMC5883_E_ACC_INVALID_CFG INT8_C(-5)
#define QMC5883_E_GYRO_INVALID_CFG INT8_C(-6)
#define QMC5883_E_ACC_GYR_INVALID_CFG INT8_C(-7)
#define QMC5883_E_INVALID_SENSOR INT8_C(-8)
#define QMC5883_E_CONFIG_LOAD INT8_C(-9)
#define QMC5883_E_INVALID_PAGE INT8_C(-10)
#define QMC5883_E_INVALID_FEAT_BIT INT8_C(-11)
#define QMC5883_E_INVALID_INT_PIN INT8_C(-12)
#define QMC5883_E_SET_APS_FAIL INT8_C(-13)
#define QMC5883_E_AUX_INVALID_CFG INT8_C(-14)
#define QMC5883_E_AUX_BUSY INT8_C(-15)
#define QMC5883_E_SELF_TEST_FAIL INT8_C(-16)
#define QMC5883_E_REMAP_ERROR INT8_C(-17)
#define QMC5883_E_GYR_USER_GAIN_UPD_FAIL INT8_C(-18)
#define QMC5883_E_SELF_TEST_NOT_DONE INT8_C(-19)
#define QMC5883_E_INVALID_INPUT INT8_C(-20)
#define QMC5883_E_INVALID_STATUS INT8_C(-21)
#define QMC5883_E_CRT_ERROR INT8_C(-22)
#define QMC5883_E_ST_ALREADY_RUNNING INT8_C(-23)
#define QMC5883_E_CRT_READY_FOR_DL_FAIL_ABORT INT8_C(-24)
#define QMC5883_E_DL_ERROR INT8_C(-25)
#define QMC5883_E_PRECON_ERROR INT8_C(-26)
#define QMC5883_E_ABORT_ERROR INT8_C(-27)
#define QMC5883_E_GYRO_SELF_TEST_ERROR INT8_C(-28)
#define QMC5883_E_GYRO_SELF_TEST_TIMEOUT INT8_C(-29)
#define QMC5883_E_WRITE_CYCLE_ONGOING INT8_C(-30)
#define QMC5883_E_WRITE_CYCLE_TIMEOUT INT8_C(-31)
#define QMC5883_E_ST_NOT_RUNING INT8_C(-32)
#define QMC5883_E_DATA_RDY_INT_FAILED INT8_C(-33)
#define QMC5883_E_INVALID_FOC_POSITION INT8_C(-34)

/*! @name QMC5883L register addresses */
#define QMC5883L_MAG_X_LSB_ADDR UINT8_C(0x00)
#define QMC5883L_MAG_X_MSB_ADDR UINT8_C(0x01)
#define QMC5883L_MAG_Y_LSB_ADDR UINT8_C(0x02)
#define QMC5883L_MAG_Y_MSB_ADDR UINT8_C(0x03)
#define QMC5883L_MAG_Z_LSB_ADDR UINT8_C(0x04)
#define QMC5883L_MAG_Z_MSB_ADDR UINT8_C(0x05)
#define QMC5883L_STATUS_1_ADDR UINT8_C(0x06)
#define QMC5883L_TEMP_LSB_ADDR UINT8_C(0x07)
#define QMC5883L_TEMP_MSB_ADDR UINT8_C(0x08)
#define QMC5883L_CONTROL1_ADDR UINT8_C(0x09)
#define QMC5883L_CONTROL2_ADDR UINT8_C(0x0A)
#define QMC5883L_SET_ADDR UINT8_C(0x0B)
#define QMC5883L_CHIP_ID_ADDR UINT8_C(0x0D)

/*! @name QMC5883P register addresses */
#define QMC5883P_CHIP_ID_ADDR UINT8_C(0x00)
#define QMC5883P_MAG_X_LSB_ADDR UINT8_C(0x01)
#define QMC5883P_MAG_X_MSB_ADDR UINT8_C(0x02)
#define QMC5883P_MAG_Y_LSB_ADDR UINT8_C(0x03)
#define QMC5883P_MAG_Y_MSB_ADDR UINT8_C(0x04)
#define QMC5883P_MAG_Z_LSB_ADDR UINT8_C(0x05)
#define QMC5883P_MAG_Z_MSB_ADDR UINT8_C(0x06)
#define QMC5883P_STATUS_ADDR UINT8_C(0x09)
#define QMC5883P_CONTROL1_ADDR UINT8_C(0x0A)
#define QMC5883P_CONTROL2_ADDR UINT8_C(0x0B)

#define QMC5883P_CHIP_ID UINT8_C(0x80)
#define QMC5880P_I2C_ADDR (0x2c)

#define QMC5883L_CHIP_ID UINT8_C(0xFF)
#define QMC5880L_I2C_ADDR (0x0D)

#define QMC5883_MAG_ODR_10HZ UINT8_C(0x00)
#define QMC5883_MAG_ODR_50HZ UINT8_C(0x01)
#define QMC5883_MAG_ODR_100HZ UINT8_C(0x02)
#define QMC5883_MAG_ODR_200HZ UINT8_C(0x03)

#define QMC5883_SUSPEND_MODE UINT8_C(0x00)
#define QMC5883_NORMAL_MODE UINT8_C(0x01)
#define QMC5883_SINGLE_MODE UINT8_C(0x02)
#define QMC5883_CONTINUS_MODE UINT8_C(0x03)

#define QMC5883_OSR_8 UINT8_C(0x00)
#define QMC5883_OSR_4 UINT8_C(0x01)
#define QMC5883_OSR_2 UINT8_C(0x02)
#define QMC5883_OSR_1 UINT8_C(0x03)

#define QMC5883_FILTER_PERFERMANCE_DEP_1 UINT8_C(0x00)
#define QMC5883_FILTER_PERFERMANCE_DEP_2 UINT8_C(0x01)
#define QMC5883_FILTER_PERFERMANCE_DEP_4 UINT8_C(0x02)
#define QMC5883_FILTER_PERFERMANCE_DEP_8 UINT8_C(0x03)

/*!
 * @brief Bus communication function pointer which should be mapped to
 * the platform specific write functions of the user
 *
 * @param[in] reg_addr      : Register address to which the data is read.
 * @param[in] reg_data     : Pointer to data buffer in which data to be read
 *                            is stored.
 * @param[in] len           : Number of bytes of data to be read.
 *
 */
typedef QMC5883_INTF_RETURN_TYPE (*qmc5883_read_fptr_t)(uint8_t reg_addr, uint8_t *reg_data, uint16_t len);

/*!
 * @brief Bus communication function pointer which should be mapped to
 * the platform specific write functions of the user
 *
 * @param[in] reg_addr      : Register address to which the data is written.
 * @param[in] reg_data     : Pointer to data buffer in which data to be written
 *                            is stored.
 * @param[in] len           : Number of bytes of data to be written.
 *
 */
typedef QMC5883_INTF_RETURN_TYPE (*qmc5883_write_fptr_t)(uint8_t reg_addr, uint8_t *reg_data, uint16_t len);

/*!
 * @brief Delay function pointer which should be mapped to
 * delay function of the user
 *
 * @param[in] period              : Delay in microseconds.
 *
 */
typedef QMC5883_INTF_RETURN_TYPE (*qmc5883_delay_fptr_t)(uint32_t period);

/* work mode */
enum QMC5883_Mode
{
    suspend,
    normal,
    single,
    continus
};

enum QMC5883_CHIP
{
    UNKNOWN,
    QMC5883L,
    QMC5883P
};

/* sensor range */
enum QMC5883_Range
{
    range_30_Gauss,
    range_12_Gauss,
    range_8_Gauss,
    range_2_Gauss
};

/* sensor odr */
enum QMC5883_odr
{
    ODR_10Hz,
    ODR_50Hz,
    ODR_100Hz,
    ODR_200Hz
};

/* little endian */
struct QMC5883_ADC_16bit
{
    uint8_t lsb;
    uint8_t msb;
};

union QMC5883_ADC_DATA
{
    int16_t axis_adc;
    struct QMC5883_ADC_16bit axis_adc_2part;
};

typedef struct QMC5883_MAG_DATA
{
    union QMC5883_ADC_DATA mag_x;
    union QMC5883_ADC_DATA mag_y;
    union QMC5883_ADC_DATA mag_z;
} qmc5883_mag_data_t;

typedef struct QMC5883_DEV
{
    uint8_t i2c_addr;

    uint8_t chip_id;

    enum QMC5883_CHIP chip_type;

    /*! To store interface pointer error */
    QMC5883_INTF_RETURN_TYPE intf_rslt;

    /*! Read function pointer */
    qmc5883_read_fptr_t read;

    /*! Write function pointer */
    qmc5883_write_fptr_t write;

    /*!  Delay function pointer */
    qmc5883_delay_fptr_t delay_ms;

} qmc5883_dev;

#endif
